#!/usr/bin/perl -I /opt/hp/nv/lib/perl
#
# (C) Copyright 2010- Hewlett-Packard Development Company, L.P.
#
# $Id: config.pm 16374 2012-03-21 22:22:12Z chantal.tremblay@hp.com $
#

use Net::Ping;

package config;
require Exporter;

our @ISA = qw(Exporter);
our @EXPORT = qw(
		log_event
		instance_log_event
		get_force_flag
		);
our %EXPORT_TAGS = ('all' => [qw(
    log_event
    get_force_flag
    grep_in_file
    grep_count_in_file
    cluster_type
    bright_version
    cmsh_check   
    get_active_HN
    get_passive_HN
    $nvpath
    get_enclosure_OAs
    Trim
    instance_log_event
    is_valid_user
    get_hyperthreading
)]);
our @EXPORT_OK = (@{$EXPORT_TAGS{'all'}});

our $version = "config.pm 2.00";

use 5.008000;
use strict;
use warnings;

use POSIX;

use constant CPUINFO => "/proc/cpuinfo";

our $nvpath = "/opt/hp/nv"; # If all scripts use this, we only have to change it here

my $log_dir = "$nvpath/config/log/";
my $log_name = "neoview_config";
my $force_run="$nvpath/instance/force_flag";

# add support for a separate instance log file.
my $instance_log_dir = "$nvpath/instance/";
my $instance_log_name = "instance_log";

sub log_event {
my $log_file;

        my($message) =  @_;

        $log_file = "$log_dir/$log_name";

        # Open the log file
        open(LOG, ">>$log_file") || die "Cannot open log file $log_file\n";

        # Get the current time for log message
        my $Mark = localtime();

        # Now print it
        printf(LOG "%s: %s\n", $Mark, $message);

        # Done. Now close it and exit
        close(LOG);

        return 0;
}

sub instance_log_event {
my $instance_log_file;

        my($message) =  @_;

	if (!-e $instance_log_dir ) {
		my $cmd = "/bin/mkdir -p $instance_log_dir";
		system "$cmd";
                if (WIFEXITED($?) && (WEXITSTATUS($?) != 0)) {
                        print "Unable to execute $cmd: WEXITSTATUS($?)";
                        print "Unable to log the following message: $message";
			die();
                }
        }

        $instance_log_file = "$instance_log_dir/$instance_log_name";

        # Open the log file
        open(LOG, ">>$instance_log_file") 
            || die "Cannot open log file $instance_log_file";

        # Get the current time for log message
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
        my $Mark = sprintf("%d-%02d-%02d_%02d:%02d:%02d", 
                            $year+1900,$mon+1, $mday, $hour, $min, $sec);

        # Now print it
        printf(LOG "%s: %s\n", $Mark, $message);

        # Done. Now close it and exit
        close(LOG);

        return 0;
}


#
# This sub checks to see if we are forcing a re-run
# by checking the value that is set in the force_flag file
# force-run=0 - do not force the re-run
# force-run=1 - force the script to re-run
#
sub get_force_flag
{

        #
        # first check that file exists; if not proceed as if it wasn't set.
        #
	if (!-e $force_run) {
		instance_log_event("$0: WARNING: $force_run file not found.  Assuming flag is not set.\n");
		return(0);
	}

        #
        # open file and pull out flag value
        #
        unless (open(IFH,$force_run)) { 
		instance_log_event("$0: ERROR: Can't open file $force_run: $!\n");
		die();
	}
        while (<IFH>) # loop through the whole file
        {
                my $line = $_;
                chomp($line);
                next if ($line =~ /^\s*$/);
                next if ($line =~ /^\#/);

                if ($line =~ /^force_run/) {
                        my @fields = split('=', $line);
        		close(IFH);
                        return($fields[1]);
                }
        }

	instance_log_event("$0: WARNING: Force_run flag not found in file $force_run.  Assuming flag is not set.\n");
        close(IFH);
	return(0);
}

##
## Grep in a filename for a string, returning found (0) or not found (1)
##
## Arguments: Two
##              @_[0] - filename
##              @_[1] - string to look for
##
sub grep_in_file($$)
{
    my ($fn, $str) = @_;
    my $cmd = "grep \"$str\" $fn";

    `$cmd > /dev/null 2>&1`;

    return ((WIFEXITED($?) && (WEXITSTATUS($?) != 0)) ? 1 : 0);
}

##
## Grep in a filename for a string, returning count of number of 
## matches found.  
## NOE:!!!  It is expected that that caller knows that the
## string is present, possibly by calling grep_in_file first
## before trying to get a count!
##
## Arguments: Two
##              @_[0] - filename
##              @_[1] - string to look for
##
sub grep_count_in_file($$)
{
    my ($fn, $str) = @_;
    my $cmd = "grep -c \"$str\" $fn";

    my $ret = `$cmd`;

    return ($ret);
}

##
## Get the type of cluster this script is running on (e.g. XC, Bright, ...?)
##
## Return Value: 0 - Bright Computing Cluster
##               1 - XC Cluster
##               2 - Unknown/something else TBD
##
sub cluster_type
{
    return (0) if (-e "/etc/cm-release");
    return (1) if (-e "/etc/hptc-release");
    return (2);
}

##
##
##
sub bright_version
{
    return (-1) unless (-e "/etc/cm-release");

    my $cmd = "egrep -o v[0-9\\.]+ /etc/cm-release | egrep -o [0-9\\.]+";
    chomp(my $ver = `$cmd`);

    return ($ver);
}

sub get_active_HN() {
  my @headNode = ();
  my $activeHeadNode= ();
  my $cmdOutput = `cmsh -c 'device list'`;
  if($? >> 8) {
    print "Error running cmsh command\n";
  }
  my @cmdOutputArr = split ("\n", $cmdOutput);

  foreach my $cmdOutLine (@cmdOutputArr) {
    if( $cmdOutLine =~ /^MasterNode/) {
      my($type,$hostname) = split(/\s+/, $cmdOutLine);
      push(@headNode, $hostname);
    }
  }

  foreach my $eachHN (@headNode) {
    my $pdshOutput = `pdsh -w $eachHN 'cmha status'`;
    my $grepOut    = `echo "$pdshOutput" | grep 'running in active'`;
    if (($? >> 8) == 0) {
      $activeHeadNode = $eachHN;
    }
  }
  return $activeHeadNode;
}

sub get_passive_HN() {
  my @headNode = ();
  my $activeHeadNode= ();
  my $cmdOutput = `cmsh -c 'device list'`;
  if($? >> 8) {
    print "Error running cmsh command\n";
  }
  my @cmdOutputArr = split ("\n", $cmdOutput);

  foreach my $cmdOutLine (@cmdOutputArr) {
    if( $cmdOutLine =~ /^MasterNode/) {
      my($type,$hostname) = split(/\s+/, $cmdOutLine);
      push(@headNode, $hostname);
    }
  }

  foreach my $eachHN (@headNode) {
    my $pdshOutput = `pdsh -w $eachHN 'cmha status'`;
    my $grepOut    = `echo "$pdshOutput" | grep 'running in passive'`;
    if (($? >> 8) == 0) {
      $activeHeadNode = $eachHN;
    }
  }
  return $activeHeadNode;
}

sub cmsh_check() {
  my $service   = `service cmd status 2>&1`;
  if ($? >> 8) {
    print "Error: cmdaemon service is not running\n";
    return 0;
  }

  my $cmdOutput = `cmsh -c 'help' 2>&1`;
  my $err       = $? >> 8;
  if ($err) {
    return 0;
  }
  else {
    return 1;
  }
}

#others
sub is_valid_user($)
{
    my $user = shift;

    my $cmd = "cmsh -c 'user show user $user' >/dev/null 2>&1";

    system($cmd);

    return (WEXITSTATUS($?) == 0);
}
## Fill a list of Onboard Administrator IP addresses, where the list will
## contain a single OA IP for each blades enclosure.  This function will
## check for a pingable active or standby OA based on a known address
## scheme.
sub get_enclosure_OAs($)
{
    my $oa_list_ref = shift;
    my $first_sn = 10;
    my $last_sn = 255;
    my $MSABASEIP_FMT = "172.31.%d.%d";
    my $errs = 0;

    my $pinger = Net::Ping->new();

    # Try each possible OA IP address
    for my $rack ($first_sn .. $last_sn)
    {
        my $oaadded = 0;
        my $oaip_act = sprintf($MSABASEIP_FMT, $rack, 1); # Active OA IP address
        my $oaip_stb = sprintf($MSABASEIP_FMT, $rack, 2); # Standby OA IP address

        last unless($pinger->ping($oaip_act) || $pinger->ping($oaip_stb));

        # Looks like there's an active OA
        if ($pinger->ping($oaip_act))
        {
            instance_log_event("$0: INFO: Trying the OA with IP address $oaip_act" . "\n");

            push(@{$oa_list_ref}, $oaip_act);
            $oaadded = 1;
        }

        else
        {
            instance_log_event("$0: WARNING: Couldn't ping primary OA $oaip_act" . "\n");
            $errs++;
        }

        # Looks like there's a standby OA
        if ($pinger->ping($oaip_stb))
        {
            instance_log_event("$0: INFO: Trying the OA with IP address $oaip_stb" . "\n");

            my $oainst = BladesEnc::OA->new(IP => $oaip_stb, PASSWORD => "admin123", ERRMODE => "return");

            if ($oainst == -1)
            {
                instance_log_event("$0: WARNING: Couldn't connect to OA $oaip_act using default credentials\n");
                $errs++;
            }

            else
            {
                if ($oaadded == 0)
                {
                    push(@{$oa_list_ref}, $oaip_stb);
                    $oaadded = 1;
                }
            }
        }

        else
        {
            instance_log_event("$0: WARNING: Couldn't ping standby OA $oaip_stb" . "\n");
            $errs++;
        }
    }

    $pinger->close();

    return ($errs);
}

##
## Trim leading and trailing whitespace from a string.
##
## Arguments: One - required
##              @_[0] - String to trim
##
## Return Value: String, trimmed
##
sub Trim($)
{
    my $string = shift;

    $string =~ s/^\s+//;
    $string =~ s/\s+$//;

    return ($string);
}

#
# This sub determines whether hyperthreading has been disabled.
#
# return 1: enabled
#        0: disabled
sub get_hyperthreading
{

my @fields;
my ($sibling_val, $core_val);

        # now let's check cpuinfo on first processor; if the sibling value
	# and core value are the same then we can assume that hyperthreading
	# has been disabled
        open (FILE, CPUINFO) or die "Cannot open cpuinfo: $!\n";

        while (<FILE>) {
                chomp;

                # now lets look for the lines starting with 'Master'
                if (/^siblings/) {
                	@fields = split /:/;
                        $sibling_val = $fields[1];
                }
                elsif (/^cpu cores/) {
                	@fields = split /:/;
                        $core_val = $fields[1];
                }

		if (defined $sibling_val && defined $core_val) {
			return 0 if ($sibling_val == $core_val);
                        return 1;
		}
        }

        close(FILE);
        return 0;
}

1;
